package com.xuecheng.media.service.impl;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.vod.model.v20170321.GetPlayInfoResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.content.model.dto.TeachplanMediaDTO;
import com.xuecheng.api.media.model.dto.MediaDTO;
import com.xuecheng.api.media.model.qo.QueryMediaModel;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.enums.content.CourseAuditEnum;
import com.xuecheng.common.exception.ExceptionCast;
import com.xuecheng.common.util.StringUtil;
import com.xuecheng.media.agent.ContentApiAgent;
import com.xuecheng.media.common.constant.MediaErrorCode;
import com.xuecheng.media.common.utils.AliyunVODUtil;
import com.xuecheng.media.convert.MediaConvert;
import com.xuecheng.media.entity.Media;
import com.xuecheng.media.mapper.MediaMapper;
import com.xuecheng.media.service.MediaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 媒资信息 服务实现类
 * </p>
 *
 * @author itcast
 */
@Slf4j
@Service
public class MediaServiceImpl extends ServiceImpl<MediaMapper, Media> implements MediaService {

    @Value("${aliyun.region}")
    private String region;
    @Value("${aliyun.accessKeyId}")
    private String accessKeyId;
    @Value("${aliyun.accessKeySecret}")
    private String accessKeySecret;

    @Autowired
    private ContentApiAgent contentApiAgent;

    @Autowired
    private MediaMapper mediaMapper;


    /*
     * 业务分析：
     *   1.判断关键数据
     *       companyId、filename、fileId
     *   2.判断业务数据
     *       媒资信息
     *           判断媒资信息是否存在：fileid
     *   3.将dto转为po数据
     *   4.获得url地址并保存到media表中（不实现）
     *   5.保存媒资信息并返回dto数据
     * */
    @Override
    public MediaDTO createMedia(MediaDTO dto) {
        //1.判断关键数据
        //     companyId、filename、fileId
        String fileId = dto.getFileId();
        if (ObjectUtils.isEmpty(dto.getCompanyId()) ||
                StringUtil.isBlank(fileId) ||
                StringUtil.isBlank(dto.getFilename())
        ) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }


        // 2.判断业务数据
        //     媒资信息
        //         判断媒资信息是否存在：fileid
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Media::getFileId, fileId);

        int count = this.count(queryWrapper);

        if (count > 0) {
            ExceptionCast.cast(MediaErrorCode.E_140008);
        }

        // 3.将dto转为po数据
        Media media = MediaConvert.INSTANCE.dto2entity(dto);


        // 4.保存媒资信息并返回dto数据
        boolean result = this.save(media);
        if (!result) {
            ExceptionCast.cast(MediaErrorCode.E_140001);
        }

        Media po = this.getById(media.getId());

        MediaDTO resultDTO = MediaConvert.INSTANCE.entity2dto(po);


        return resultDTO;
    }

    /*
     * 步骤分析：
     *  1.是否需要开启事务
     *  2.判断关键数据
     *       分页数据
     *       查询条件
     *  3.构建mp分页对象
     *  4.构建查询条件对象LambdaQueryWrapper
     *  5.查询数据
     *  6.获得数据并封装返回结果
     *       封装PageVo数据
     * */
    @Override
    public PageVO queryMediaList(PageRequestParams params, QueryMediaModel model, Long companyId) {
        //1.是否需要开启事务
        // 查询无需开启事务
        // 2.判断关键数据
        //      分页数据
        //      查询条件

        // 2.1 判断分页数据
        Long pageNo = params.getPageNo();
        Integer pageSize = params.getPageSize();

        if (ObjectUtils.isEmpty(pageNo) || pageNo < 0) {
            params.setPageNo(PageRequestParams.DEFAULT_PAGE_NUM);
        }

        if (ObjectUtils.isEmpty(pageSize) || pageSize < 0) {
            params.setPageSize(PageRequestParams.DEFAULT_PAGE_SIZE);
        }

        // 2.2.构建查询条件对象LambdaQueryWrapper
        // 完成第四部中的构建查询条件
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();

        // 完整版
        // select * from course_base where name = ? and auditStatus = ? and companyId = ?
        // if (StringUtil.isNotBlank(model.getCourseName())) {
        //     queryWrapper.eq(CourseBase::getName,model.getCourseName());
        // }
        //
        // if (StringUtil.isNotBlank(model.getAuditStatus())) {
        //     queryWrapper.eq(CourseBase::getAuditStatus,model.getAuditStatus());
        // }

        // 简版
        queryWrapper.like(StringUtil.isNotBlank(model.getFilename()), Media::getFilename, model.getFilename());
        queryWrapper.eq(StringUtil.isNotBlank(model.getAuditStatus()), Media::getAuditStatus, model.getAuditStatus());
        queryWrapper.eq(StringUtil.isNotBlank(model.getType()), Media::getType, model.getType());
        queryWrapper.eq(!(ObjectUtils.isEmpty(companyId)), Media::getCompanyId, companyId);

        // 3.构建mp分页对象
        Page<Media> page = new Page<>(params.getPageNo(), params.getPageSize());

        // 5.查询数据
        Page<Media> pageResult = this.page(page, queryWrapper);

        // 获得当前页的集合数据
        List<Media> records = pageResult.getRecords();

        // 查询数据的总记录数
        long total = pageResult.getTotal();

        // 将po数据转为dto数据
        List<MediaDTO> dtos = Collections.EMPTY_LIST;

        if (!(CollectionUtils.isEmpty(records))) {
            dtos = MediaConvert.INSTANCE.entitys2dtos(records);
        }

        // 6.获得数据并封装返回结果
        //      封装PageVo数据
        PageVO pageVO = new PageVO(dtos, total, params.getPageNo(), params.getPageSize());

        return pageVO;
    }

    /**
     * @param mediaId   - 媒资的id
     * @param companyId - 公司令牌
     * @return - 媒资资源地址
     */
    @Override
    public String getVODUrl(Long mediaId, Long companyId) {
        // 1.判断业务数据
        if (ObjectUtils.isEmpty(mediaId)) {
            ExceptionCast.cast(CommonErrorCode.E_100101);
        }
        // 2.根据媒资id获得媒资信息
        Media media = getById(mediaId);
        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(CommonErrorCode.E_100104);
        }

        // 3.如果公司id不为空，对其进行判断
        if (!(ObjectUtils.isEmpty(companyId))) {
            if (!(ObjectUtils.nullSafeEquals(media.getCompanyId(), companyId))) {
                ExceptionCast.cast(CommonErrorCode.E_100108);
            }
        }

        String playUrl = getPlayUrl(media.getFileId());

        // 4.返回媒资的资源地址
        return playUrl;
    }


    /**
     * 业务分析：
     * 1，判断关键数据的合法性：mediaId、companyId
     * 2，判断业务数据
     * 媒资信息
     * 判断是否存在
     * 判断是否删除
     * 判断审核状态：只有审核通过不能删除
     * 判断媒资信息是否有绑定课程计划数据
     * 绑定媒资和课程计划数据：content.表： teachplan_media
     *
     * @param mediaId   - 媒资id
     * @param companyId - 公司令牌
     */
    @Override
    @Transactional
    public void removeMedia(Long mediaId, Long companyId) {
        //1,判断关键数据的合法性：mediaId、companyId
        //2，判断业务数据
        //媒资信息是否存在
        //媒资信息是否删除
        Media media = verifyMedia(mediaId, companyId);

        //判断审核状态：只有审核通过不能删除
        String auditStatus = media.getAuditStatus();
        if (CourseAuditEnum.AUDIT_COMMIT_STATUS.getCode().equals(auditStatus)) {
            //TODO：我没找到媒资信息审核状态的枚举
            //不过我知道写死不太好
            //然后我对比了一下发现和课程计划的审核状态码差不多于是我就借用那个了
            ExceptionCast.cast(MediaErrorCode.E_140015);
        }
        //判断媒资信息是否有绑定课程计划数据
        //并且在查询过程中：如果查到了直接删掉
        RestResponse<TeachplanMediaDTO> response = contentApiAgent.getById(mediaId);
        if (response.isSuccessful()){
            //进来，说明媒资绑定了课程计划
            //先把绑定了课程计划的媒资删了
            contentApiAgent.removeById(mediaId);
        }
        //删除媒资信息
        int result = mediaMapper.deleteById(mediaId);
        if (result<=0){
            ExceptionCast.cast(CommonErrorCode.E_110009);
        }
    }


    /**
     * 首先判断媒资id和公司id是否为空
     * 然后判断媒资信息是否存在
     * 再判断是否删除
     * @param mediaId   - 媒资id
     * @param companyId - 公司令牌
     */
    private Media verifyMedia(Long mediaId, Long companyId) {
        //判断关键数据的合法性：mediaId、companyId
        verifyMediaIdAndCompanyId(mediaId, companyId);
        //2.判断业务数据
        //2.1判断媒资信息是否存在
        LambdaQueryWrapper<Media> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Media::getId, mediaId);
        queryWrapper.eq(Media::getCompanyId, companyId);
        Media media = this.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(media)) {
            ExceptionCast.cast(MediaErrorCode.E_140005);
        }
        //媒资信息是否删除
        String status = media.getStatus();
        if (CommonEnum.DELETE_FLAG.getCode().equals(status)) {
            ExceptionCast.cast(MediaErrorCode.E_140010);
        }

        return media;
    }


    /**
     * 获得资源url地址
     *
     * @param videoId - 资源id
     * @return - 资源url地址
     */
    private String getPlayUrl(String videoId) {

        String playUrl = "";
        try {

            DefaultAcsClient client =
                    AliyunVODUtil.initVodClient(region, accessKeyId, accessKeySecret);

            GetPlayInfoResponse response = AliyunVODUtil.getPlayInfo(client, videoId);

            List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();

            if (!(ObjectUtils.isEmpty(playInfoList))) {
                GetPlayInfoResponse.PlayInfo playInfo = playInfoList.get(0);
                playUrl = playInfo.getPlayURL();
            }

            // 需要通过redis来保存url数据（代实现）

        } catch (Exception e) {
            ExceptionCast.cast(MediaErrorCode.E_140014);
        }
        return playUrl;
    }


    /**
     * 判断mediaId和companyId是否存在
     *
     * @param mediaId   - 媒资id
     * @param companyId - 公司令牌
     */
    void verifyMediaIdAndCompanyId(Long mediaId, Long companyId) {
        if (ObjectUtils.isEmpty(mediaId)) {
            ExceptionCast.cast(MediaErrorCode.E_140009);
        }

        if (ObjectUtils.isEmpty(companyId)) {
            ExceptionCast.cast(CommonErrorCode.E_403001);
        }
    }

}
